package org.example.lotterysystem.service.mq;

import org.example.lotterysystem.common.utils.JacksonUtil;
import org.example.lotterysystem.dao.dataobject.DeadLetterMessageDO;
import org.example.lotterysystem.dao.mapper.DeadLetterMessageMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

import static org.example.lotterysystem.common.config.DirectRabbitConfig.*;

@Component
@RabbitListener(queues = DLX_QUEUE_NAME)
public class DlxReceiver {

    private static final Logger log = LoggerFactory.getLogger(DlxReceiver.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private DeadLetterMessageMapper deadLetterMessageMapper;

    private static final String EXCHANGE_NAME = "DlxDirectExchange";
    private static final String ROUTING_KEY = "DlxDirectRouting";

    @RabbitHandler
    public void process(Map<String, String> message) {
        log.info("开始处理死信队列消息: {}", message);

        try {
            // 1. 将消息持久化到数据库
            DeadLetterMessageDO entity = new DeadLetterMessageDO();
            entity.setExchange(EXCHANGE_NAME);
            entity.setRoutingKey(ROUTING_KEY);
            entity.setMessageContent(JacksonUtil.writeValueAsString(message));
            entity.setStatus(0); // 待处理状态
            deadLetterMessageMapper.insert(entity);

            log.info("死信消息已持久化到数据库, ID: {}", entity.getId());

            // 2. 这里可以添加额外的异常处理逻辑，比如发送报警通知等

        } catch (Exception e) {
            log.error("处理死信消息异常", e);
            // 即使保存失败也不重新投递，避免无限循环
            // 可以考虑记录日志或发送系统报警
        }

//        // 死信队列的处理方法
//        logger.info("开始处理异常消息！");
//        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING, message);
//        // 该流程是有问题的，在这里只是为了演示处理过程中发生异常：消息堆积-》处理异常-》消息重发
//        // 正确的流程（扩展）：
//        // 1、接收到异常消息，可以将异常消息存放到数据库表中
//        // 2、存放后，当前异常消息消费完成，死信队列消息处理完成，但异常消息被我们持久化存储到表中了
//        // 3、解决异常
//        // 4、完成脚本任务，判断异常消息表中是否存在数据，如果存在，表示有消息未完成，此时处理消息
//        // 5、处理消息：将消息发送给普通队列进行处理

    }
    /**
     * 定时任务：处理积压的死信消息
     */
    @Scheduled(fixedDelay = 30000) // 每30秒执行一次
    public void processPendingMessages() {
        // 1. 查询待处理的死信消息（限制每次处理数量）
        List<DeadLetterMessageDO> messages = deadLetterMessageMapper.selectPendingMessages(100);

        if (messages.isEmpty()) {
            log.debug("没有待处理的死信消息");
            return;
        }

        log.info("开始批量处理死信消息，数量: {}", messages.size());

        for (DeadLetterMessageDO message : messages) {
            try {
                // 2. 更新为处理中状态
                message.setStatus(1); // 处理中
                message.setRetryCount(message.getRetryCount() + 1);
                message.setLastRetryTime(new Date());
                deadLetterMessageMapper.updateById(message);

                // 3. 重新投递消息
                Map<String, String> content = JacksonUtil.readMapValue(message.getMessageContent(),String.class,String.class);
                rabbitTemplate.convertAndSend(
                        message.getExchange(),
                        message.getRoutingKey(),
                        content
                );

                // 4. 更新为处理成功状态
                message.setStatus(2); // 处理成功
                deadLetterMessageMapper.updateById(message);

                log.info("死信消息重新投递成功, ID: {}", message.getId());

            } catch (Exception e) {
                log.error("处理死信消息失败, ID: " + message.getId(), e);

                // 更新为处理失败状态
                message.setStatus(3); // 处理失败
                message.setErrorMsg(e.getMessage());
                deadLetterMessageMapper.updateById(message);

                // 可以根据重试次数决定是否放弃或发送报警
                if (message.getRetryCount() >= 3) {
                    log.warn("死信消息已达到最大重试次数, ID: {}", message.getId());
                    // 可以发送报警通知管理员
                }
            }
        }
    }
}